package snakegame;

import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Properties;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;

public class GamePanel extends JPanel {

  public JPanel pNoord;
  public JPanel pCenter;
  public JLabel lScore;
  public int score = 0;
  public static int scoreErbijAlsJeEet = 1;
  public static final String PROPERTIES_FILE = "snake.properties";
  public int aantalVakkenHor = 15;
  public int aantalVakkenVert = 15;
  public static final int aantalVakkenHorMin = 4;
  public static final int aantalVakkenVertMin = 4;
  public static final int aantalVakkenHorMax = 500;
  public static final int aantalVakkenVertMax = 500;
  public Vakje[][] vakken;
  public static final int R_GEEN = -1;
  public static final int R_LINKS = 0;
  public static final int R_RECHTS = 1;
  public static final int R_OMHOOG = 2;
  public static final int R_OMLAAG = 3;
  public int richting = R_GEEN;
  public static int klokSpeed = 200;
  public static final int klokSpeedMax = 5000;
  public static final int klokSpeedMin = 1;
  public static Timer klok;
  public static int aantalEten = 2;
  public static int staartErbijAlsJeEet = 1;
  public static final int staartErbijAlsJeEetMin = 1;
  public static final int staartErbijAlsJeEetMax = 1000;
  public static int beginLengte = 2;
  public static int beginLengteMin = 2;
  public static int beginLengteMax = 1000;
  public static int bodyTimerBegin = beginLengte; //Wordt ook bij Properties gedaan

/*  @Override
  public void start(){
    this.add(new GamePanel());
  }*/

  public GamePanel() {
    //Constructor
//    this.setBorder(new LineBorder(Color.black));
    if (Main.debug) {
      Main.drukaf("Border is gemaakt...");
    }
    BorderLayout layout = new BorderLayout();
    this.setLayout(layout);
    if (Main.debug) {
      Main.drukaf("Layout is gemaakt...");
    }
    //
    doeProperties();
    //
    pNoord = new JPanel();
    lScore = new JLabel();
    doeScoreLBL();
    pNoord.add(lScore);
    this.add(pNoord, BorderLayout.NORTH);
    //
    maakPCenter();
    this.add(pCenter, BorderLayout.CENTER);
    //
    initVakjes();
    //
    if (Main.pda) {
      Main.frame.addMouseListener(new MouseAdapter() {

        @Override
        public void mouseClicked(MouseEvent e) {
          geklikt(e.getX(),e.getY());
          //throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public void mousePressed(MouseEvent e) {
          geklikt(e.getX(),e.getY());
          //throw new UnsupportedOperationException("Not supported yet.");
        }
      });
    } else {
      this.setFocusable(true); //ja is nodig !
      //want ik zet de keylistener niet op frame maar op this !
      this.addKeyListener(new KeyListener() {

        @Override
        public void keyPressed(KeyEvent e) {
          if (Main.debug) {
            Main.drukaf("GamePanel.KeyAdapter: Knopje Gedrukt XD");
          }
          if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
            doeRichting(R_RECHTS);
          }
          if (e.getKeyCode() == KeyEvent.VK_LEFT) {
            doeRichting(R_LINKS);
          }
          if (e.getKeyCode() == KeyEvent.VK_UP) {
            doeRichting(R_OMHOOG);
          }
          if (e.getKeyCode() == KeyEvent.VK_DOWN) {
            doeRichting(R_OMLAAG);
          }
        }

        public void keyTyped(KeyEvent e) {
          //throw new UnsupportedOperationException("Not supported yet.");
        }

        public void keyReleased(KeyEvent e) {
          //throw new UnsupportedOperationException("Not supported yet.");
        }
      });
    }
    this.addComponentListener(new ComponentAdapter() {

      @Override
      public void componentResized(ComponentEvent e) {
        doeResizeDingen();
      }
    });

    if (Main.debug) {
      Main.drukaf("klok maken... (klokSpeed: " + klokSpeed + ")");
    }

    klok = new Timer(klokSpeed, new ActionListener() {

      public void actionPerformed(ActionEvent e) {
        doeStep();
      }
    });
    klok.setRepeats(true);
    klok.start();
  }

  public void doeStep() {
    beweegSlang();
    bodyDelenMin();
    this.repaint();
  }

  public void geklikt(int x, int y){
    //Dit voor de PDA
    //want de pijltoetsen doen het niet op mn PDA
    //Klik op het scherm om de rechting te veranderen
    if (y<this.getHeight()/3){
      doeRichting(R_OMHOOG);
    }
    if (y>(this.getHeight()/3)*2){
      doeRichting(R_OMLAAG);
    }
    if (x<this.getWidth()/3){
      doeRichting(R_LINKS);
    }
    if (x>(this.getWidth()/3)*2){
      doeRichting(R_RECHTS);
    }
  }

  public void beweegSlang() {
    if (richting == R_GEEN) {
      if (Main.debug) {
        Main.drukaf("GamePanel.beweegSlang: Slang beweegt niet...");
      }
      return;
    }
    Point hoofdBeginPunt = waarIsWat(Vakje.HOOFD);
    int hoofdNieuwX = hoofdBeginPunt.x;
    int hoofdNieuwY = hoofdBeginPunt.y;
    if (richting == R_RECHTS) {
      hoofdNieuwX = hoofdBeginPunt.x + 1;
      hoofdNieuwY = hoofdBeginPunt.y;
    }
    if (richting == R_LINKS) {
      hoofdNieuwX = hoofdBeginPunt.x - 1;
      hoofdNieuwY = hoofdBeginPunt.y;
    }
    if (richting == R_OMHOOG) {
      hoofdNieuwX = hoofdBeginPunt.x;
      hoofdNieuwY = hoofdBeginPunt.y - 1;
    }
    if (richting == R_OMLAAG) {
      hoofdNieuwX = hoofdBeginPunt.x;
      hoofdNieuwY = hoofdBeginPunt.y + 1;
    }
    int watIsDaar = watIsWaar(hoofdNieuwX, hoofdNieuwY);
    switch (watIsDaar) {
      case Vakje.ETEN: {
        score += scoreErbijAlsJeEet;
        doeScoreLBL();
        bodyTimerBegin += staartErbijAlsJeEet;
        maakNieuweEten();
        break;
      }
      case Vakje.MUUR:
      case Vakje.BODY:
      case Vakje.STAART: {
        gaDood();
        break;
      }
    }
    //Vakje Waar Hoofd was --> Body
    vakken[hoofdBeginPunt.x][hoofdBeginPunt.y].setWat(Vakje.BODY);
    vakken[hoofdBeginPunt.x][hoofdBeginPunt.y].setBodyTimer(bodyTimerBegin);
    //Hoofd verplaatsen
    vakken[hoofdNieuwX][hoofdNieuwY].setWat(Vakje.HOOFD);
  }

  public void bodyDelenMin() {
    //ArrayList bodyDelen = new ArrayList();
    for (int a = 0; a < aantalVakkenVert; a++) {
      for (int b = 0; b < aantalVakkenHor; b++) {
        if (Vakje.BODY == vakken[b][a].getWat() || Vakje.STAART == vakken[b][a].getWat()) {
          //bodyDelen.add(new Point(b, a));
          if (vakken[b][a].getWat() == Vakje.BODY) {
            vakken[b][a].bodyTimerMin();
            if (vakken[b][a].getBodyTimer() < 1) {
              if (Main.debug) {
                Main.drukaf("GamePanel.bodyDelenMin --> bodyDeel wordt Staart");
              }
              vakken[b][a].setWat(Vakje.STAART);
            }
          } else {
            //Staart is weg
            if (Main.debug) {
              Main.drukaf("GamePanel.bodyDelenMin --> Staat wordt Gewoon");
            }
            vakken[b][a].setWat(Vakje.GEWOON);
          }
        }
      }
    }
  }

  public void gaDood() {
    klok.stop();
    lScore.setText("<html>Score: " + score + "<br>GAME OVER !!!</html>");
  }

  public void maakNieuweEten() {
    //eerst checken of je de Nieuwe Eten wel kwijt kan XD
    ArrayList mogelijkePlekken = new ArrayList();
    for (int a = 0; a < aantalVakkenVert; a++) {
      for (int b = 0; b < aantalVakkenHor; b++) {
        if (Vakje.GEWOON == vakken[b][a].getWat()) {
          mogelijkePlekken.add(new Point(b, a));
        }
      }
    }
    if (mogelijkePlekken.size() == 0) {
      if (Main.debug) {
        Main.drukaf("GamePanel.maakNieuweEten->Fout: Geen Plek !!");
      }
    } else {
      //Kies een plekje uit
      int dobbelsteen = (int) (mogelijkePlekken.size() * Math.random());
      Point plekkie = (Point) mogelijkePlekken.get(dobbelsteen);
      vakken[plekkie.x][plekkie.y].setWat(Vakje.ETEN);
    }
  }

  public void doeRichting(int foo) {
    richting = foo;
    if (Main.debug) {
      Main.drukaf("Richting aangepast...");
    }
  }

  public void doeProperties() {
    if (Main.debug) {
      Main.drukaf("GamePanel.doeProperties...");
    }
    java.net.URL deURL = null;
    Properties props = new Properties();
    try {
      deURL = GamePanel.class.getResource(PROPERTIES_FILE);
      InputStream in = deURL.openStream();
      props.load(in);
      in.close();
    } catch (Exception ex) {
      System.out.println("GamePanel.doePropties: Fout bij het lezen van de Properties-file\n(file: " + PROPERTIES_FILE + ")\nFout: " + ex);
    }


    if (props.getProperty("aantalVakkenHor") != null && Main.isInt(props.getProperty("aantalVakkenHor"))) {
      int foo = Integer.parseInt(props.getProperty("aantalVakkenHor"));
      if (foo < aantalVakkenHorMin) {
        aantalVakkenHor = aantalVakkenHorMin;
      } else if (foo > aantalVakkenHorMax) {
        aantalVakkenHor = aantalVakkenHorMax;
      } else {
        aantalVakkenHor = foo;
      }
      if (Main.debug) {
        Main.drukaf("GamePanel-Props: aantalVakkenHor is nu: " + aantalVakkenHor);
      }
    }
    if (props.getProperty("aantalVakkenVert") != null && Main.isInt(props.getProperty("aantalVakkenVert"))) {
      int foo = Integer.parseInt(props.getProperty("aantalVakkenVert"));
      if (foo < aantalVakkenVertMin) {
        aantalVakkenVert = aantalVakkenVertMin;
      } else if (foo > aantalVakkenVertMax) {
        aantalVakkenVert = aantalVakkenVertMax;
      } else {
        aantalVakkenVert = foo;
      }
      if (Main.debug) {
        Main.drukaf("GamePanel-Props: aantalVakkenVert is nu: " + aantalVakkenVert);
      }
    }
    if (props.getProperty("klokSpeed") != null && Main.isInt(props.getProperty("klokSpeed"))) {
      int foo = Integer.parseInt(props.getProperty("klokSpeed"));
      if (foo < klokSpeedMin) {
        klokSpeed = klokSpeedMin;
      } else if (foo > klokSpeedMax) {
        klokSpeed = klokSpeedMax;
      } else {
        klokSpeed = foo;
      }
      if (Main.debug) {
        Main.drukaf("GamePanel-Props: klokSpeed is nu: " + klokSpeed);
      }
    }

    if (props.getProperty("scoreErbijAlsJeEet") != null && Main.isInt(props.getProperty("scoreErbijAlsJeEet"))) {
      int foo = Integer.parseInt(props.getProperty("scoreErbijAlsJeEet"));
      scoreErbijAlsJeEet = foo;
      if (Main.debug) {
        Main.drukaf("GamePanel-Props: scoreErbijAlsJeEet is nu: " + scoreErbijAlsJeEet);
      }
    }

    if (props.getProperty("staartErbijAlsJeEet") != null && Main.isInt(props.getProperty("staartErbijAlsJeEet"))) {
      int foo = Integer.parseInt(props.getProperty("staartErbijAlsJeEet"));
      if (foo < staartErbijAlsJeEetMin) {
        staartErbijAlsJeEet = staartErbijAlsJeEetMin;
      } else if (foo > staartErbijAlsJeEetMax) {
        staartErbijAlsJeEet = staartErbijAlsJeEetMax;
      } else {
        staartErbijAlsJeEet = foo;
      }
      if (Main.debug) {
        Main.drukaf("GamePanel-Props: staartErbijAlsJeEet is nu: " + staartErbijAlsJeEet);
      }
    }

    if (props.getProperty("beginLengte") != null && Main.isInt(props.getProperty("beginLengte"))) {
      int foo = Integer.parseInt(props.getProperty("beginLengte"));
      if (foo < beginLengteMin) {
        beginLengte = beginLengteMin;
      } else if (foo > beginLengteMax) {
        beginLengte = beginLengteMax;
      } else {
        beginLengte = foo;
      }
      bodyTimerBegin = beginLengte;
      if (Main.debug) {
        Main.drukaf("GamePanel-Props: beginLengte is nu: " + beginLengte);
      }
    }

    if (Main.debug) {
      Main.drukaf("GamePanel.doeProperties: Properties Gedaan\nFile: " + PROPERTIES_FILE);
    }
  }

  public void maakPCenter() {
    pCenter = new JPanel();
    GridLayout cLayout = new GridLayout();
    cLayout.setColumns(aantalVakkenHor);
    cLayout.setRows(aantalVakkenVert);
    pCenter.setLayout(cLayout);
    vakken = new Vakje[aantalVakkenHor][aantalVakkenVert];
    for (int vert = 0; vert < aantalVakkenVert; vert++) {
      for (int hor = 0; hor < aantalVakkenHor; hor++) {
        vakken[hor][vert] = new Vakje();
        vakken[hor][vert].setWat(Vakje.GEWOON);
        pCenter.add(vakken[hor][vert]);
      }
    }
    if (Main.debug) {
      Main.drukaf("GamePanel.maakPCenter is gedaan...");
    }
  }

  public void initVakjes() {
    //maak muren
    if (Main.debug) {
      Main.drukaf("GamePanel.initVakjes...");
    }
    boolean maakMuren = true;
    if (maakMuren) {
      //BOVEN EN ONDER
      for (int a = 0; a < aantalVakkenHor; a++) {
        vakken[a][0].setWat(Vakje.MUUR);
        vakken[a][aantalVakkenVert - 1].setWat(Vakje.MUUR);
      }
      //LINKS EN RECHTS
      for (int b = 0; b < aantalVakkenVert; b++) {
        vakken[0][b].setWat(Vakje.MUUR);
        vakken[aantalVakkenHor - 1][b].setWat(Vakje.MUUR);
      }
    }
    //de Slang
    if (Main.debug) {
      Main.drukaf("GamePanel.initVakjes --> Hoofd Maken");
    }
    vakken[2][2].setWat(Vakje.HOOFD);
    //Eten
    if (Main.debug) {
      Main.drukaf("GamePanel.initVakjes --> Eten Maken");
    }
    for (int q = 1; q <= aantalEten; q++) {
      maakNieuweEten();
    }
    if (Main.debug) {
      Main.drukaf("GamePanel.initVakjes Gedaan :P");
    }
  }

  public java.awt.Point waarIsWat(int watZoekIk) {
    for (int a = 0; a < aantalVakkenVert; a++) {
      for (int b = 0; b < aantalVakkenHor; b++) {
        if (watZoekIk == vakken[b][a].getWat()) {
          return new java.awt.Point(b, a);
        }
      }
    }
    return null;
  }

  public int watIsWaar(int x, int y) {
    return vakken[x][y].getWat();
  }

  public void doeScoreLBL() {
    if (Main.pda) {
      lScore.setText("(PDA-MODE) Score: " + score);
    } else {
      lScore.setText("Score: " + score);
    }
    if (Main.debug) {
      Main.drukaf("GamePanel.doeScoreLBL is gedaan...");
    }
  }

  public static void doeResizeDingen() {
    ///Dingen
    if (Main.debug) {
      Main.drukaf("ResizeDingen -> Gedaan");
    }
  }
  /////////////KLEUR
  /*
  int R = HexToR("#FFFFFF");
  int G = HexToG("#FFFFFF");
  int B = HexToB("#FFFFFF");
   */

  public static int HexToR(String h) {
    return Integer.parseInt((cutHex(h)).substring(0, 2), 16);
  }

  public static int HexToG(String h) {
    return Integer.parseInt((cutHex(h)).substring(2, 4), 16);
  }

  public static int HexToB(String h) {
    return Integer.parseInt((cutHex(h)).substring(4, 6), 16);
  }

  public static String cutHex(String h) {
    if (h.charAt(0) == '#') {
      return h.substring(1, 7);
    } else {
      return h;
    }
  }
}
